use std::{
  cmp::{max, min},
  str::FromStr,
};

use aok::Result;
use stripe::{
  CreatePaymentIntent, CreatePaymentIntentAutomaticPaymentMethods,
  CreatePaymentIntentAutomaticPaymentMethodsAllowRedirects, Currency, CustomerId, PaymentIntent,
  PaymentIntentStatus, PaymentMethodId,
};

use super::super::{
  exchange::{self, BASE},
  stripe::STRIPE,
};

// 欧元 貌似最多充值一万
pub const MAX: u64 = 1_000_000;
pub const MIN: u64 = 5_00;

// pub async fn payment_method_default(uid: u64) -> Result<Option<Vec<u8>>> {
//   Ok(m::q01!(format!(
//     "SELECT v FROM payStripePaymentMethod WHERE uid={uid} ORDER BY ts DESC LIMIT 1"
//   )))
// }

pub struct Topup {
  pub rate: u64,
  pub n: u64,
  pub status: PaymentIntentStatus,
}

pub async fn topup(uid: u64, n: u64, card: u64) -> Result<Option<Topup>> {
  let payment_mothod = m::q01!(format!(
    "SELECT v FROM payStripePaymentMethod WHERE uid={uid} AND id={card}"
  ));

  topup_by_payment_method(uid, n, payment_mothod).await
}

pub async fn topup_by_payment_method(
  uid: u64,
  n: u64,
  payment_method: Option<Vec<u8>>,
) -> Result<Option<Topup>> {
  let n = min(max(n, MIN), MAX);
  let (customer, rate): (Option<Vec<u8>>, _) = trt::join!(
    m::q01(
      format!("SELECT v FROM payStripeCustomer WHERE id={uid}",),
      vec![],
    ),
    exchange::eur()
  );
  if let Some(customer) = customer
    && let Some(payment_method) = payment_method
  {
    let mut opt = CreatePaymentIntent::new(n as _, Currency::EUR);
    opt.payment_method = Some(PaymentMethodId::from_str(&format!(
      "pm_{}",
      b62::e(payment_method)
    ))?);

    opt.confirm = Some(true);
    opt.automatic_payment_methods = Some(CreatePaymentIntentAutomaticPaymentMethods {
      allow_redirects: Some(CreatePaymentIntentAutomaticPaymentMethodsAllowRedirects::Never),
      enabled: true,
    });
    opt.customer = Some(CustomerId::from_str(&format!("cus_{}", b62::e(customer)))?);

    let pay = PaymentIntent::create(&STRIPE, opt).await?;
    // pi_3OZa6OBS6OLyeF2Q25jW4ECR
    let id = b62::d(&pay.id.as_str()[3..])?;
    let n = pay.amount as u64;
    let status = pay.status;

    let topup = n * BASE / rate;
    status == PaymentIntentStatus::Succeeded;
    dbg!(&pay);
    dbg!(("TODO", id, n, status, status as u8, rate, topup));
    return Ok(Some(Topup { n, rate, status }));
  }

  Ok(None)
}
